package com.iqiyi.pps.epg.core.rpc.program;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iqiyi.pps.epg.api.model.web.program.*;
import com.iqiyi.pps.epg.api.model.web.query.TFilter;
import com.iqiyi.pps.epg.api.model.web.query.TPage;
import com.iqiyi.pps.epg.api.model.web.query.TResponse;
import com.iqiyi.pps.epg.api.server.web.program.ProgramDirectorWebService;
import com.iqiyi.pps.epg.core.model.program.*;
import com.iqiyi.pps.epg.core.service.program.IProgramAsyncService;
import com.iqiyi.pps.epg.core.service.program.IProgramDirectorResourceService;
import com.iqiyi.pps.epg.core.service.program.IProgramDirectorService;
import com.iqiyi.pps.epg.core.service.program.ProgramService;
import com.iqiyi.pps.epg.core.utils.ApiDirectorUtil;
import com.iqiyi.pps.epg.core.utils.ApplicationContextUtil;
import com.iqiyi.pps.epg.core.utils.Constants;
import com.iqiyi.pps.epg.core.utils.WriteSystemLogUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.thrift.TException;
import org.hibernate.StaleObjectStateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Created by jiegang on 2017/3/3.
 */
public class ProgramDirectorWebServiceImpl implements ProgramDirectorWebService.Iface {
    private static Logger logger = LoggerFactory.getLogger(ProgramDirectorWebServiceImpl.class);

    public static final int DEL_FAIL = 0;           // 删除失败
    public static final int RESPONSE_SUC = 1;

    public static final int ERROR_NO_ENTITY = -1;
    public static final int ERROR_DELETED_ENTITY = -2;
    public static final int ERROR_WRONG_ENTITY = -1001;
    public static final int ERROR_WRONG_RESOURCE = -1002;
    public static final int ERROR_EXCEPTION = -999;
    public static final int ERROR_API_EXCEPTION = -1003;
    public static final int ERROR_OLD_DATA = -1004;
    public static final int ERROR_DIRECTOR_RELEASE = -1005;
    public static final int ERROR_AUTO_CREATE_PREVIEW_URL = -2;
    public static final int ERROR_COMMENTARY_COUNT_OVERFLOW = -998;
    public static final int ERROR_COMMENTARY_IS_PLAYING = -997;

    public static final int WARN_DATA_ALREADY = -2001;
    public static final int WARN_RESOURCE_USEING = -2002;
    public static final int WARN_PROGRAM_END = -2003;

    public static final int ERROR_RESOURCE_PLAYCOUNTS = -3001;
    public static final int ERROR_MAINRESOURCE_NONE = -3002;
    public static final int ERROR_SET_MAINRESOURCE = -3003;

    public static final String COMMENTARY_DEFAULT_NAME = "解说信号源%s";


    private ProgramService getProgramService() {
        return WriteSystemLogUtil.getInstance().getProgramService();
    }

    private IProgramDirectorService getPdService() {
        return WriteSystemLogUtil.getInstance().getPdService();
    }

    private IProgramDirectorResourceService getPrService() {
        return WriteSystemLogUtil.getInstance().getPrService();
    }

    private IProgramAsyncService getAsyncService() {
        return WriteSystemLogUtil.getInstance().getProgramAsyncService();
    }

    private ConcurrentLinkedQueue<ProgramDirectorEffect> queue;

    @Override
    public int addDirectorEntity(TProgramDirector entity) throws TException {
        int entityId = ERROR_NO_ENTITY;
        try {
            ProgramDirector pd = getPdService().getByProgramQipuId(entity.getProgramQipuId());
            if (pd == null) {
                pd = new ProgramDirector();
                pd.setProgramName(entity.getProgramName());
                pd.setProgramQipuId(entity.getProgramQipuId());
                pd.setStartPlayTime(Timestamp.valueOf(entity.getStartPlayTime()));
                pd.setStopPlayTime(Timestamp.valueOf(entity.getStopPlayTime()));
                pd.setSource(entity.getSource());
                pd.setDelay(entity.getDelay());
                if (entity.getOutputUrl() == null) {
                    String outputUrl = ApiDirectorUtil.doRegisterOutputUrl(entity.getProgramQipuId());
                    entity.setOutputUrl(outputUrl);
                }
                pd.setOutputUrl(entity.getOutputUrl() == null ? "" : entity.getOutputUrl());
                pd.setRecycleUrl(pd.getOutputUrl());
                pd.setOutputPreviewUrl(entity.getOutputPreviewUrl());
                pd.setOutputStreamType(entity.getOutputStreamType() == null ? "RESOLUTION_720P" : entity.getOutputStreamType());
                pd.setPlayStatus(ProgramDirector.READY_PLAY);
                pd.setAddTime(new Timestamp(System.currentTimeMillis()));
                JSONObject params = new JSONObject();
                params.put("ID", pd.getProgramQipuId());
                params.put("NAME", pd.getProgramName());
                params.put("DELAY", pd.getDelay());
                params.put("ADDRESS", pd.getOutputUrl());
                params.put("RESOLUTION", pd.getOutputStreamType());
                params.put("BEGINTIME", pd.getStartPlayTime().getTime() / 1000);
                params.put("ENDTIME", pd.getStopPlayTime().getTime() / 1000);
                params.put("CREATEBY", entity.getOpUser());
                params.put("MAINSOURCE", "");

                String dbt_region = ProgramData.DBT_REGION_BEIJING;
                try {
                    ProgramService service = getProgramService();
                    ProgramData programData = service.findProgramDataByQipuId(pd.getProgramQipuId());
                    dbt_region = StringUtils.strip(StringUtils.isBlank(programData.getDbtRegion()) ?
                            ProgramData.DBT_REGION_BEIJING : programData.getDbtRegion());
                } catch (Exception e) {
                    logger.info("[addDirectorEntity][get dbt_region] e = " + e);
                }

                JSONObject retJson = ApiDirectorUtil.doStartDirector(params.toJSONString(), entity.getProgramQipuId() + "",
                        dbt_region);
                if (retJson != null && Constants.CODE_SUC.equals(retJson.get("error_code"))) {
                    pd.setOutputPreviewUrl(retJson.getString("result"));
                    entityId = getPdService().addProgramDirector(pd);
                    if (entityId > 0) {
                        ProgramDirectorResource resource = ProgramDirectorResource.createBackupResource(pd.getId(), pd.getProgramQipuId());
                        int resourceId = notifyAddResource(resource, entity.getOpUser());
                        if (resourceId < 1) {
                            logger.warn("[addDirectorEntity][auto create backup resource fail:{}]", resourceId);
                        }
                        // 创建导播默认素材
                        createDefaultEffects(entityId, entity.getProgramQipuId());
                    }
                } else {
                    writeProgramLogByQipuId(entity.getProgramQipuId(), Constants.LogType.PROGRAM_THIRDPART_API_FAIL.getIndex(),
                            "director | startprogram | " + retJson);
                    return ERROR_API_EXCEPTION;
                }

                writeDirectorLog(entityId, Constants.DirectorLogType.NOTIFY_START_PROGRAM.getIndex(), retJson + "|" + params.toString());

            }else if(pd.getPlayStatus() == 3){ //导播结束
                return ERROR_DIRECTOR_RELEASE;
            } else {
                entityId = 0;
            }
        } catch (Exception e) {
            logger.error("addDirectorEntity", e);
            entityId = ERROR_EXCEPTION;
        }
        return entityId;
    }

    @Override
    public int editDirectorEntity(TProgramDirector entity) throws TException {
        int ret = RESPONSE_SUC;
        try {
            ProgramDirector pd = getPdService().getByProgramQipuId(entity.getProgramQipuId());
            if (pd == null) {
                logger.error("editDirectorEntity not exist entity", entity.getProgramQipuId());
                return ERROR_NO_ENTITY;
            }

            boolean isChanged = isDirectorChanged(pd, entity);

            DirectorEditAssist editAssist = new DirectorEditAssist(pd);

            pd.setProgramName(entity.getProgramName());
            pd.setDelay(entity.getDelay());
            pd.setOutputUrl(entity.getOutputUrl());
            pd.setOutputStreamType(entity.getOutputStreamType());
            editAssist.checkAgain(pd);
            if (editAssist.isChange()) {
//                JSONObject params = new JSONObject();
//                params.put("ID", pd.getProgramQipuId());
//                params.put("NAME", pd.getProgramName());
//                params.put("DELAY", pd.getDelay());
//                params.put("ADDRESS", pd.getOutputUrl());
//                params.put("RESOLUTION", pd.getOutputStreamType());
//                params.put("BEGINTIME", pd.getStartPlayTime().getTime() / 1000);
//                params.put("ENDTIME", pd.getStopPlayTime().getTime() / 1000);
//                params.put("UPDATEBY", entity.getOpUser());
//                boolean retData = ApiDirectorUtil.doUpdateDirector(params.toJSONString(), pd.getProgramQipuId() + "");
//                writeDirectorLog(pd.getId(), Constants.DirectorLogType.NOTIFY_UPDATE_PROGRAM.getIndex(), retData + "|" + params.toString());
//                if (!retData) {
//                    return ERROR_API_EXCEPTION;
//                }
                //      pd.setResourceId(entity.getResourceId());
                getPdService().updateProgramDirector(pd);
                getPdService().updateCurResourceId(pd.getId(), entity.getResourceId());

                if (isChanged) {
                    getPrService().deleteCommentaryAllByDirectorId(entity.getId());
                }
            }
        } catch (Exception e) {
            logger.error("editDirectorEntity", e);
            ret = ERROR_EXCEPTION;
        }
        return ret;
    }

    @Override
    public int delDirectorEntity(int id) throws TException {
        try {
            ProgramDirector programDirector = getPdService().getById(id);
            if (programDirector == null) {
                return ERROR_NO_ENTITY;
            }
            programDirector.setPlayStatus(ProgramDirector.DELETE_FLAG);
            getPdService().updateProgramDirector(programDirector);
            return RESPONSE_SUC;
        } catch (Exception e) {
            logger.error("delDirectorEntity", e);
            return ERROR_EXCEPTION;
        }
    }

    @Override
    public int updateDirectorMainResource(long programQipuId, int mainResourceId, String opUser) throws TException {
        try {
            ProgramDirector pd = getPdService().getByProgramQipuId(programQipuId);
            if (pd == null) {
                return ERROR_NO_ENTITY;
            }

            ProgramDirectorResource pr = getPrService().get(mainResourceId);
            if (pr.getSignalType() != ProgramDirectorResource.SINGAL_TYPE_ZHIBO && pr.getSignalType() != ProgramDirectorResource.SINGAL_TYPE_LIUDIZHI) {
                return ERROR_WRONG_ENTITY;
            }
            if (pd.getMainResourceId() == mainResourceId) {
                return RESPONSE_SUC;
            }

            if (pd.getPlayStatus() == ProgramDirector.START_PLAY) {
                ProgramDirectorResource playResource = getPrService().get(pd.getResourceId());
                if (playResource.getSignalType() == ProgramDirectorResource.SINGAL_TYPE_DIANBO) {
                    return ERROR_SET_MAINRESOURCE;
                }
            }

            JSONObject params = new JSONObject();
            params.put("ID", pd.getProgramQipuId());
            params.put("NAME", pd.getProgramName());
            params.put("DELAY", pd.getDelay());
            params.put("ADDRESS", pd.getOutputUrl());
            params.put("RESOLUTION", pd.getOutputStreamType());
            params.put("BEGINTIME", pd.getStartPlayTime().getTime() / 1000);
            params.put("ENDTIME", pd.getStopPlayTime().getTime() / 1000);
            params.put("UPDATEBY", opUser);
            params.put("MAINSOURCE", mainResourceId);
            boolean retData = ApiDirectorUtil.doUpdateDirector(params.toJSONString(), pd.getProgramQipuId() + "");
            writeDirectorLog(pd.getId(), Constants.DirectorLogType.NOTIFY_UPDATE_PROGRAM.getIndex(), retData + "|" + params.toString());
            if (!retData) {
                return ERROR_API_EXCEPTION;
            }
            getPdService().updateMainResourceId(pd.getId(), mainResourceId);
            return RESPONSE_SUC;
        } catch (Exception e) {
            logger.error("updateDirectorMainResource", e);
            return ERROR_EXCEPTION;
        }
    }


    @Override
    public int addResourceEntity(TProgramDirectorResource thriftEntity) throws TException {
        if (thriftEntity != null) {
            try {
                ProgramDirectorResource entity = new ProgramDirectorResource();

                if (thriftEntity.getSignalType() == ProgramDirectorResource.SINGAL_TYPE_LIUDIZHI && StringUtils.isEmpty(thriftEntity.getSignalPreviewUrl())) {
                    JSONObject responseJson = ApiDirectorUtil.startPreviewUrl(thriftEntity.getProgramQipuId() + "", thriftEntity.getSignalUrl());
                    writeDirectorLog(thriftEntity.getDirectorId(), Constants.DirectorLogType.NOTIFY_START_PREVIEW_URL.getIndex(), responseJson + "|" + thriftEntity.getSignalUrl());
                    if (responseJson != null && Constants.CODE_SUC.equals(responseJson.get("error_code"))) {
                        String previewUrl = (String) responseJson.get("result");
                        entity.setSignalPreviewUrl(previewUrl);
                    } else {
                        return ERROR_AUTO_CREATE_PREVIEW_URL;
                    }
                } else {
                    entity.setSignalPreviewUrl(thriftEntity.getSignalPreviewUrl() != null ? thriftEntity.getSignalPreviewUrl() : "");
                }

                entity.setDirectorId(thriftEntity.getDirectorId());
                entity.setProgramQipuId(thriftEntity.getProgramQipuId());
                entity.setSignalLegoId(thriftEntity.getSignalLegoId());
                entity.setSignalId(thriftEntity.getSignalId() != null ? thriftEntity.getSignalId() : "");
                entity.setSignalType(thriftEntity.getSignalType());
                //entity.setSnapshotUrl(thriftEntity.getSnapshotUrl() != null ? thriftEntity.getSnapshotUrl() : "");
                entity.setIsBackup(thriftEntity.getIsBackup());
                entity.setSignalName(thriftEntity.getSignalName() != null ? thriftEntity.getSignalName() : "");
                entity.setSignalUrl(thriftEntity.getSignalUrl() != null ? thriftEntity.getSignalUrl() : "");
                //entity.setProductStatusUrl(thriftEntity.getProductStatusUrl() != null ? thriftEntity.getProductStatusUrl() : "");
                entity.setIsDefaultBackup(thriftEntity.getIsDefaultBackup());
                entity.setPlayCounts(thriftEntity.getPlayCounts());

                entity.setResourceType(ProgramDirectorResource.RESOURCE_TYPE_SIGNAL);


                if (entity.getIsBackup() == ProgramDirectorResource.IS_BACKUP && entity.getIsDefaultBackup() == ProgramDirectorResource.IS_DEFAULT_BACKUP) {
                    List<ProgramDirectorResource> list = getPrService().findByDefault(entity.getDirectorId());
                    if (list != null || list.size() > 0) {
                        for (ProgramDirectorResource resource : list) {
                            resource.setIsDefaultBackup(ProgramDirectorResource.NON_DEFAULT_BACKUP);
                            getPrService().update(resource);
                        }
                    }
                }

                int entityId = notifyAddResource(entity, thriftEntity.getOpUser());
                return entityId;
            } catch (Exception e) {
                logger.error("addResourceEntity", e);
                return ERROR_EXCEPTION;
            }
        }
        return ERROR_NO_ENTITY;
    }

    @Override
    public int updateResourcePlayCounts(int id, int playCounts) throws TException {
        try {
            ProgramDirectorResource entity = getPrService().get(id);
            if (entity == null || entity.getIsDeleted() == ProgramDirectorResource.IS_DELETE) {
                return ERROR_NO_ENTITY;
            }
            entity.setPlayCounts(playCounts);

            boolean result = ApiDirectorUtil.updateSource(id+"", entity.getProgramQipuId()+"", playCounts+"");
            if (result) {
                getPrService().update(entity);
                return RESPONSE_SUC;
            } else {
                return ERROR_API_EXCEPTION;
            }
        } catch (Exception e) {
            logger.error("updateResourcePlayCounts", e);
            return ERROR_EXCEPTION;
        }
    }

    private int notifyAddResource(ProgramDirectorResource entity, String opUser) {
        ProgramDirectorResource newEntity = getPrService().add(entity);
        int entityId = newEntity.getId();
        if (entityId > 0) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("ID", entityId);
            jsonObject.put("Name", entity.getSignalName());
            if (entity.getSignalType() == ProgramDirectorResource.SINGAL_TYPE_LIUDIZHI) {
                jsonObject.put("MODE", 0);
                jsonObject.put("ADDRESS", entity.getSignalUrl());
            } else {
                jsonObject.put("MODE", entity.getSignalType());
                jsonObject.put("ADDRESS", "");
            }
            jsonObject.put("TYPE", entity.getIsBackup());
            jsonObject.put("QIPUID", entity.getSignalId());
            jsonObject.put("PROGRAMID", entity.getProgramQipuId());
            jsonObject.put("REPEAT", entity.getPlayCounts());
            jsonObject.put("CREATEBY", opUser);

            JSONObject responseJson = ApiDirectorUtil.addSource(jsonObject.toJSONString(), entity.getProgramQipuId() + "");
            String url = "";
            writeDirectorLog(entity.getDirectorId(), Constants.DirectorLogType.NOTIFY_ADD_SOURCE.getIndex(), responseJson + "|" + jsonObject.toString());
            if (responseJson != null && Constants.CODE_SUC.equals(responseJson.get("error_code"))) {
                url = (String) responseJson.get("result");
                if (entity.getSignalType() == ProgramDirectorResource.SINGAL_TYPE_ZHIBO || entity.getSignalType() == ProgramDirectorResource.SINGAL_TYPE_LIUDIZHI) {
                    entity.setSnapshotUrl(url);
                } else if (entity.getSignalType() == ProgramDirectorResource.SINGAL_TYPE_DIANBO) {
                    entity.setProductStatusUrl(url);
                }
                getPrService().update(entity);
            } else {
                entity.setIsDeleted(ProgramDirectorResource.IS_DELETE);
                getPrService().update(entity);
                entityId = -1;
            }
        }
        return entityId;
    }

    private int notifyAddEffectResource(ProgramDirectorEffect entity, String opUser, int entityId, boolean needLog) {
//        int entityId = getPdService().addProgramDirectorEffect(entity);
        if (entityId > 0) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("ID", entityId);
            jsonObject.put("NAME", entity.getName());
            jsonObject.put("PROGRAMID", entity.getProgramQipuId());
            jsonObject.put("TYPE", entity.getType());

            if (entity.getType() == 2) {
                jsonObject.put("ADDRESS", encodeToUTF8(entity.getUrl()));
            } else {
                jsonObject.put("ADDRESS", entity.getUrl());
            }

            jsonObject.put("MEDIA", entity.getExtraInfo());
            jsonObject.put("LOCATION", entity.getLocation());
            jsonObject.put("CREATEBY", opUser);


            JSONObject responseJson = ApiDirectorUtil.addResource(entity.getProgramQipuId() + "", jsonObject.toJSONString());
            String url = "";
            if (needLog) {
                writeDirectorLog(entity.getDirectorId(), Constants.DirectorLogType.NOTIFY_ADD_EFFECT.getIndex(), responseJson + "|" + jsonObject.toString());
            }
            if (responseJson == null || !Constants.CODE_SUC.equals(responseJson.get("error_code"))) {
                entityId = -1;
            }
        }
        return entityId;
    }

    private int notifyUpdateEffectResource(ProgramDirectorEffect entity, String opUser) {
        int entityId = entity.getId();
        if (entityId > 0) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("ID", entityId);

            // 字幕进行字符转码
            if (entity.getType() == 2) {
                jsonObject.put("ADDRESS", encodeToUTF8(entity.getUrl()));
            } else {
                jsonObject.put("ADDRESS", entity.getUrl());
            }

            jsonObject.put("MEDIA", entity.getExtraInfo());
            jsonObject.put("LOCATION", entity.getLocation());
            jsonObject.put("TYPE", entity.getType());
            jsonObject.put("PROGRAMID", entity.getProgramQipuId());
            jsonObject.put("UPDATEBY", opUser);

            JSONObject responseJson = ApiDirectorUtil.updateResource(entity.getProgramQipuId() + "",
                    entity.getId() + "",
                    jsonObject.toJSONString());
            String url = "";
            writeDirectorLog(entity.getDirectorId(), Constants.DirectorLogType.NOTIFY_UPDATE_EFFECT.getIndex(), responseJson + "|" + jsonObject.toString());
            if (responseJson != null && Constants.CODE_SUC.equals(responseJson.get("error_code"))) {
//                url = (String) responseJson.get("result");
            } else {
                entityId = -1;
            }
        }
        return entityId;
    }

    private int notifyPreviewEffectResource(ProgramDirectorEffect entity, String opUser) {
        int entityId = entity.getId();
        if (entityId > 0) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("ID", entityId);

            // 字幕进行字符转码
            if (entity.getType() == 2) {
                jsonObject.put("ADDRESS", encodeToUTF8(entity.getUrl()));
            } else {
                jsonObject.put("ADDRESS", entity.getUrl());
            }

            jsonObject.put("MEDIA", entity.getExtraInfo());
            jsonObject.put("LOCATION", entity.getLocation());
            jsonObject.put("TYPE", entity.getType());
            jsonObject.put("PROGRAMID", entity.getProgramQipuId());
            jsonObject.put("UPDATEBY", opUser);

//            SimpleDateFormat sdf = new SimpleDateFormat("YYYY/MM/dd HH:mm:ss.SSS");
//            logger.info("[notifyPreviewEffectResource] start " + sdf.format(new Date()));
            JSONObject responseJson = ApiDirectorUtil.startPreview(entity.getProgramQipuId() + "",
                    entity.getId() + "",
                    jsonObject.toJSONString());
//            logger.info("[notifyPreviewEffectResource] end " + sdf.format(new Date()));
            String url = "";
//            writeDirectorLog(entity.getDirectorId(), Constants.DirectorLogType.NOTIFY_UPDATE_EFFECT.getIndex(), responseJson + "|" + jsonObject.toString());
            if (responseJson != null && Constants.CODE_SUC.equals(responseJson.get("error_code"))) {
//                url = (String) responseJson.get("result");
            } else {
                entityId = -1;
            }
        }
        return entityId;
    }

    @Override
    public int editResourceEntity(int id, int isDefaultBackup, String signalName, int playStatus) throws TException {
        try {
            ProgramDirectorResource entity = getPrService().get(id);
            if (entity != null && entity.getIsDeleted() != ProgramDirectorResource.IS_DELETE) {
                if (isDefaultBackup == ProgramDirectorResource.IS_DEFAULT_BACKUP) {
                    List<ProgramDirectorResource> list = getPrService().findByDefault(entity.getDirectorId());
                    if (list != null || list.size() > 0) {
                        for (ProgramDirectorResource resource : list) {
                            resource.setIsDefaultBackup(ProgramDirectorResource.NON_DEFAULT_BACKUP);
                            resource.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                            getPrService().update(resource);
                        }
                    }
                    entity.setIsDefaultBackup(isDefaultBackup);
                } else if (isDefaultBackup == ProgramDirectorResource.NON_DEFAULT_BACKUP) {
                }
                if (StringUtils.isNotEmpty(signalName)) {
                    entity.setSignalName(signalName);
                }
                getPrService().update(entity);
            } else {
                return ERROR_NO_ENTITY;
            }
        } catch (Exception e) {
            logger.error("editResourceEntity", e);
            return ERROR_EXCEPTION;
        }
        return RESPONSE_SUC;
    }

    @Override
    public int delResourceEntity(int id) throws TException {
        try {
            ProgramDirectorResource entity = getPrService().get(id);
            if (entity != null && entity.getIsDeleted() != ProgramDirectorResource.IS_DELETE) {
                if (entity.getIsDefaultBackup() == ProgramDirectorResource.IS_DEFAULT_BACKUP) {
                    return WARN_DATA_ALREADY;
                } else {
                    ProgramDirector director = getPdService().getById(entity.getDirectorId());
                    if (director == null || (director.getResourceId() == id) || director.getMainResourceId() == id) {
                        return WARN_RESOURCE_USEING;
                    }
                    boolean ret = ApiDirectorUtil.removeSource(String.valueOf(id), entity.getProgramQipuId() + "");
                    writeDirectorLog(entity.getDirectorId(), Constants.DirectorLogType.NOTIFY_REMOVE_SOURCE.getIndex(), ret + "|" + id);
                    if (ret) {
                        entity.setIsDeleted(ProgramDirectorResource.IS_DELETE);
                        getPrService().update(entity);

                        if (StringUtils.isNotEmpty(entity.getSignalPreviewUrl())) {
                            JSONObject jsonObject = ApiDirectorUtil.stopPreviewUrl(entity.getProgramQipuId() + "", entity.getSignalPreviewUrl());
                            writeDirectorLog(entity.getDirectorId(), Constants.DirectorLogType.NOTIFY_STOP_PREVIEW_URL.getIndex(),
                                    jsonObject + "|" + id + "|" + entity.getSignalPreviewUrl());
                        }
                    } else {
                        return DEL_FAIL;
                    }
                }
            }
        } catch (Exception e) {
            logger.error("delResourceEntity", e);
            return ERROR_EXCEPTION;
        }
        return RESPONSE_SUC;
    }

    @Override
    public int switchResourceEntity(int id, int directorId, long time, int playCounts) throws TException {
        try {
            ProgramDirector programDirector = getPdService().getById(directorId);
            if (programDirector != null) {
                if (id == programDirector.getResourceId()) {
                    return RESPONSE_SUC;
                }
                ProgramDirectorResource resource = getPrService().get(id);
                if (resource == null || resource.getIsDeleted() == ProgramDirectorResource.IS_DELETE) {
                    return ERROR_OLD_DATA;
                }

                if (playCounts != resource.getPlayCounts()) {
                    return ERROR_RESOURCE_PLAYCOUNTS;
                }

                if (resource.getSignalType() == ProgramDirectorResource.SINGAL_TYPE_DIANBO && programDirector.getMainResourceId() == 0) {
                    return ERROR_MAINRESOURCE_NONE;
                }

                Map<String, String> params = new HashMap<>();
                params.put("PID", String.valueOf(programDirector.getProgramQipuId()));
                params.put("SourceID", String.valueOf(id));
                params.put("Time", String.valueOf(time));
                JSONObject result = ApiDirectorUtil.switchSource(params);
                writeDirectorLog(directorId, Constants.DirectorLogType.NOTIFY_SWITCH_SOURCE.getIndex(), result + "|" + params);
                if (result != null && Constants.CODE_SUC.equals(result.get(ApiDirectorUtil.ERROR_CODE))) {
                    if (programDirector.getPlayStatus() == ProgramDirector.STOP_PLAY || programDirector.getPlayStatus() == ProgramDirector.READY_PLAY) {
                        programDirector.setPlayStatus(ProgramDirector.START_PLAY);
                        getPdService().updateProgramDirector(programDirector);
                    }
                    getPdService().updateCurResourceId(programDirector.getId(), id);
                } else {
                    return ERROR_EXCEPTION;
                }
            } else {
                return ERROR_NO_ENTITY;
            }
        } catch (Exception e) {
            logger.error("switchResourceEntity", e);
            return ERROR_EXCEPTION;
        }
        return RESPONSE_SUC;
    }

    @Override
    public boolean saveLog(TProgramDirectorLog entity) throws TException {
        ProgramDirectorLog logEntity = new ProgramDirectorLog();
        logEntity.setDirectorId(entity.getDirectorId());
        logEntity.setUser(entity.getUser());
        logEntity.setDescr(entity.getDescr());
        logEntity.setType(entity.getType());
        logEntity.setAddTime(new Timestamp(System.currentTimeMillis()));
        long entityId = 0;
        try {
            entityId = getPdService().addProgramDirectorLog(logEntity);
        } catch (Exception e) {
            logger.error(String.format("[saveLog][directorId=%d][logType=%d]", entity.getDirectorId(), entity.getType()), e);
        }
        return entityId > 0;
    }

    @Override
    public TProgramDirectorPage getDirectorList(TPage page, TFilter filter, boolean fullMode) throws TException {
        TProgramDirectorPage rt = getPdService().findProgramDirector(page, filter, fullMode);
        return rt;
    }

    @Override
    public TProgramDirector getDirectorEntity(int id) throws TException {
        ProgramDirector programDirector = getPdService().getById(id);
        if (programDirector == null) {
            return null;
        }
        return getPdService().transToTProgramDirector(programDirector);
    }

    @Override
    public List<TProgramDirectorResource> getDirectorResourceList(TFilter filter) throws TException {
        IProgramDirectorResourceService service = (IProgramDirectorResourceService) ApplicationContextUtil.getBean(IProgramDirectorResourceService.class);
        return service.getList(filter);
    }

    @Override
    public TProgramDirectorLogPage getLogList(TPage page, TFilter filter) throws TException {
        try {
            TProgramDirectorLogPage tProgramDirectorLogPage = getPdService().findProgramDirectorLog(page, filter);
            return tProgramDirectorLogPage;
        } catch (Exception e) {
            logger.error("getLogList", e);
            return null;
        }
    }

    @Override
    public int stopDirector(int directorId) throws TException {
        try {
            ProgramDirector programDirector = getPdService().getById(directorId);
            if (programDirector == null) {
                return ERROR_NO_ENTITY;
            }
            Map<String, Object> map = new HashMap<>();
            map.put("PID", programDirector.getProgramQipuId());
            boolean ret = ApiDirectorUtil.doStopDirector(map);
            writeDirectorLog(directorId, Constants.DirectorLogType.NOTIFY_STOP_PROGRAM.getIndex(), ret + "|" + map.toString());
            if (ret) {
                programDirector.setPlayStatus(ProgramDirector.STOP_PLAY);
                getPdService().updateProgramDirector(programDirector);
                getPdService().updateCurResourceId(programDirector.getId(), 0);
            }
            return ret ? RESPONSE_SUC : DEL_FAIL;
        } catch (Exception e) {
            logger.error("[stopDirector][directorId=" + directorId + "]", e);
            return ERROR_EXCEPTION;
        }
    }

    @Override
    public int startDirector(int directorId) throws TException {

        return RESPONSE_SUC;
    }

    @Override
    public TResponse delDirector(int directorId) throws TException {
        TResponse response = new TResponse();

        try {
            ProgramDirector programDirector = getPdService().getById(directorId);

            recycleSignalPreviewUrl(programDirector);
            response.setMsg("");
            Map<String, String> params1 = new HashMap<>();
            params1.put("PID", String.valueOf(programDirector.getProgramQipuId()));
            JSONObject result1 = ApiDirectorUtil.doReleaseDirector(params1);

            if (result1 != null && Constants.CODE_SUC.equals(result1.get(ApiDirectorUtil.ERROR_CODE))) {
                response.setCode(Constants.CODE_SUC);
                response.setMsg("第三方删除请求成功");
                updateDirectorDeleteFlag(directorId, response, programDirector);
            } else if(result1 != null && Constants.CODE_ERROR.equals(result1.get(ApiDirectorUtil.ERROR_CODE))){
                writeDirectorLog(directorId, Constants.DirectorLogType.DIRECTOR_DEL.getIndex(),
                        result1 != null ? result1.toJSONString() : "null");
                response.setCode(Constants.CODE_SUC);
                response.setMsg("第三方资源已回收");
                updateDirectorDeleteFlag(directorId, response, programDirector);

            } else {
                writeDirectorLog(directorId, Constants.DirectorLogType.DIRECTOR_DEL.getIndex(),
                        result1 != null ? result1.toJSONString() : "null");
                response.setCode(Constants.CODE_FAIL);
                response.setMsg("删除请求失败");
            }
        } catch (Exception e) {
            logger.error("Exception[directorId=" + directorId + "]", e);
            response.setCode(Constants.CODE_ERROR);
            response.setMsg("发生异常:" + response.getMsg());
        }
        logger.info("[delDirector] result1={}", response.getCode());
        return response;
    }

    /**
     * 逻辑删除导播台
     * @param directorId
     * @param response
     * @param programDirector
     */
    private void updateDirectorDeleteFlag(int directorId, TResponse response, ProgramDirector programDirector) {
        getPrService().cleanResourceByDirectorId(programDirector.getId());
        int updateSucNeedCount = 0;
        try {
            programDirector.setPlayStatus(ProgramDirector.DELETE_FLAG);
            getPdService().updateProgramDirector(programDirector);
            updateSucNeedCount = 1;
            getAsyncService().addRecycleStreamUrl(programDirector);
        } catch (StaleObjectStateException e) {
            logger.error("Exception[directorId=" + directorId + "]", e);
            response.setMsg(response.getMsg() + "|epg 第一次更新失败");
            programDirector = getPdService().getById(directorId);
            programDirector.setPlayStatus(ProgramDirector.DELETE_FLAG);
            getPdService().updateProgramDirector(programDirector);
            updateSucNeedCount = 2;
            getAsyncService().addRecycleStreamUrl(programDirector);
        } finally {
            String plusMsg = "";
            switch (updateSucNeedCount) {
                case 0:
                    response.setCode(Constants.CODE_FAIL);
                    plusMsg = "epg 重试更新失败";
                    break;
                case 1:
                    plusMsg = "epg 更新成功";
                    break;
                case 2:
                    plusMsg = "epg 重试更新成功";
                    break;
            }
            response.setMsg(response.getMsg() + "|" + plusMsg);
        }
    }

    @Override
    public TResponse releaseDirector(int directorId) {
        TResponse response = new TResponse();
        ProgramDirector programDirector = getPdService().getById(directorId);
        recycleSignalPreviewUrl(programDirector);
        Map<String, String> params1 = new HashMap<>();
        params1.put("PID", String.valueOf(programDirector.getProgramQipuId()));
        JSONObject result1 = ApiDirectorUtil.doReleaseDirector(params1);
        if (result1 != null && Constants.CODE_SUC.equals(result1.get(ApiDirectorUtil.ERROR_CODE))) {
            response.setCode(Constants.CODE_SUC);
            response.setMsg("资源回收请求成功");
            getPrService().cleanResourceByDirectorId(programDirector.getId());
            programDirector.setPlayStatus(ProgramDirector.TERMINATE_PLAY);
            getPdService().updateProgramDirector(programDirector);
            getAsyncService().addRecycleStreamUrl(programDirector);
            logger.info("[SUC] manual release [id={}][qipuId={}]", programDirector.getId(), programDirector.getProgramQipuId());
        } else {
            writeDirectorLog(directorId, Constants.DirectorLogType.DIRECTOR_DEL.getIndex(),
                    result1 != null ? result1.toJSONString() : "null");
            response.setCode(Constants.CODE_FAIL);
            response.setMsg("资源回收请求失败");
            logger.info("[FAIL] manual release [id={}][qipuId={}]", programDirector.getId(), programDirector.getProgramQipuId());
        }

        return response;
    }

    @Override
    public int switchToBackUp(int directorId) throws TException {
        int ret = RESPONSE_SUC;
        try {
            ProgramDirector programDirector = getPdService().getById(directorId);
            if (programDirector == null) {
                return ERROR_NO_ENTITY;
            }
            List<ProgramDirectorResource> list = getPrService().findByDefault(directorId);
            if (list.size() != 1) {
                return ERROR_WRONG_RESOURCE;
            }
            ProgramDirectorResource readyToPlay = list.get(0);
            if (readyToPlay.getId() == programDirector.getResourceId()) {
                logger.info("no change quick interrupt");
                return RESPONSE_SUC;
            }
            Map<String, String> params1 = new HashMap<>();
            params1.put("PID", String.valueOf(programDirector.getProgramQipuId()));
            params1.put("SourceID", String.valueOf(readyToPlay.getId()));
            JSONObject result1 = ApiDirectorUtil.switchSource(params1);
            StringBuffer sb = new StringBuffer();
            if (result1 != null && Constants.CODE_SUC.equals(result1.get(ApiDirectorUtil.ERROR_CODE))) {
                sb.append("switchsource:suc|" + params1 + "|");
                if (programDirector.getPlayStatus() == ProgramDirector.STOP_PLAY || programDirector.getPlayStatus() == ProgramDirector.READY_PLAY) {
                    programDirector.setPlayStatus(ProgramDirector.START_PLAY);
                    getPdService().updateProgramDirector(programDirector);
                }
                getPdService().updateCurResourceId(programDirector.getId(), readyToPlay.getId());
            } else {
                writeProgramLogByQipuId(programDirector.getProgramQipuId(), Constants.LogType.PROGRAM_THIRDPART_API_FAIL.getIndex(),
                        "director | switchsource | " + (result1 != null ? result1.toJSONString() : "null"));
                sb.append("switchsource:fail|" + params1 + "|");
                ret = ERROR_API_EXCEPTION;
            }
            writeDirectorLog(directorId, Constants.DirectorLogType.NOTIFY_SWITCH_BACKUP.getIndex(), ret + "||" + sb);
            return ret;
        } catch (Exception e) {
            logger.error("switchToBackUp error", e);
            return ERROR_EXCEPTION;
        }
    }

    private void writeDirectorLog(int directorId, int logType, String descr) {
        try {
            ProgramDirectorLog logEntity = new ProgramDirectorLog();
            logEntity.setDirectorId(directorId);
            logEntity.setUser(Constants.SYSTEM_USER_SIGN);
            logEntity.setDescr(descr == null ? "" : descr);
            logEntity.setType(logType);
            logEntity.setAddTime(new Timestamp(System.currentTimeMillis()));

            long entityId = getPdService().addProgramDirectorLog(logEntity);
            if (entityId == 0) {
                logger.info("[writeDirectorLog][Fail][id={}][logType={}]", directorId, logType);
            }
        } catch (Exception e) {
            logger.error(String.format("[writeDirectorLog][directorId=%d][logType=%d]", directorId, logType), e);
        }
    }

    @Override
    public int addEffect(TProgramDirectorEffect entity) throws TException {
        if (entity != null) {
            try {
                ProgramDirectorEffect pentity = new ProgramDirectorEffect();
                pentity.setDirectorId(entity.getDirectorId());
                pentity.setProgramQipuId(entity.getProgramQipuId());
                pentity.setType(entity.getType());
                pentity.setUrl(entity.getUrl());
                pentity.setName(entity.getName());
                pentity.setExtraInfo(entity.getExtraInfo());
                pentity.setLocation(entity.getLocation());
                pentity.setOpUser(entity.getOpUser());

                int entityId = getPdService().addProgramDirectorEffect(pentity);

                if (entityId > 0) {
                    notifyAddEffectResource(pentity, entity.getOpUser(), entityId, true);
                } else {
                    logger.info("[addEffect][entityId={}][entity={}] failed ", entityId, JSON.toJSONString(pentity));
                }
                return entityId;
            } catch (Exception e) {
                logger.error("[addEffect] e = " + e);
                return ERROR_EXCEPTION;
            }
        }
        return ERROR_NO_ENTITY;
    }

    @Override
    public int editEffect(int id, String url, String name, String location, String extraInfo, String status, int isPreview, String opUser) throws TException {
        try {
            ProgramDirectorEffect entity = getPdService().getEffectById(id);
            if (null != entity && entity.getStatus() != ProgramDirectorEffect.STATUS_DELETED) {
                boolean isContentChanged = false;

                if (StringUtils.isNotEmpty(url)) {
                    if (!url.equals(entity.getUrl())) {
                        isContentChanged = true;
                    }
                    entity.setUrl(url);
                }

                if (StringUtils.isNotEmpty(name)) {
                    entity.setName(name);
                }

                if (StringUtils.isNotEmpty(location)) {
                    if (!location.equals(entity.getLocation())) {
                        isContentChanged = true;
                    }
                    entity.setLocation(location);
                }

                if (StringUtils.isNotEmpty(extraInfo)) {
                    if (!extraInfo.equals(entity.getExtraInfo())) {
                        isContentChanged = true;
                    }
                    entity.setExtraInfo(extraInfo);
                }

                if (StringUtils.isNotEmpty(status) && StringUtils.isNumeric(status)) {
                    entity.setStatus(Integer.parseInt(status));
                }


                getPdService().editProgramDirectorEffect(entity);

                if (isPreview == 1) {
                    logger.info("[editEffect][isPreview][id={}]", entity.getId());
                    int ret = notifyPreviewEffectResource(entity, opUser);
                    if (ret < 0) {
                        logger.info("[editEffect] failed to preview effect");
                    }
                    // start preview
                } else if ((StringUtils.isNotEmpty(url) || StringUtils.isNotEmpty(location) ||
                        StringUtils.isNotEmpty(extraInfo)) && isContentChanged) {
                    logger.info("[editEffect][id={}][url={}][name={}][location={}][extraInfo={}][status={}][isPreview={}][opUser={}]",
                            id, url, name, location, extraInfo, status, isPreview, opUser);
                    int ret = notifyUpdateEffectResource(entity, opUser);
                    if (ret < 0) {
                        logger.warn("[editEffect] failed to update real resource");
                    }
                }
            } else {
                return ERROR_NO_ENTITY;

            }
        } catch (NumberFormatException e) {
            logger.error("[editEffect] e = " + e);
            return ERROR_EXCEPTION;
        }
        return RESPONSE_SUC;
    }

    @Override
    public int deleteEffect(int id) throws TException {
        try {
            ProgramDirectorEffect entity = getPdService().getEffectById(id);
            if (null != entity && entity.getStatus() != ProgramDirectorEffect.STATUS_DELETED) {

                boolean ret = ApiDirectorUtil.removeResource(String.valueOf(id), entity.getProgramQipuId() + "");
                writeDirectorLog(entity.getDirectorId(), Constants.DirectorLogType.NOTIFY_REMOVE_SOURCE.getIndex(), ret + "|" + id);
                if (ret) {
                    entity.setStatus(ProgramDirectorEffect.STATUS_DELETED);
                    getPdService().editProgramDirectorEffect(entity);
                } else {
                    return DEL_FAIL;
                }
            }
        } catch (Exception e) {
            logger.error("[deleteEffect] e = " + e);
            return ERROR_EXCEPTION;
        }
        return RESPONSE_SUC;
    }

    @Override
    public List<TProgramDirectorEffect> getEffectList(TFilter filter) throws TException {
        List<ProgramDirectorEffect> effectList = getPdService().getProgramDirectorEffectList(filter);

        List<TProgramDirectorEffect> results = new ArrayList<>();
        for (ProgramDirectorEffect entity : effectList) {
            results.add(transToTProgramDirectorEffect(entity));
        }
        return results;
    }

    private TProgramDirectorEffect transToTProgramDirectorEffect(ProgramDirectorEffect entity) {
        TProgramDirectorEffect effect = new TProgramDirectorEffect();
        effect.setId(entity.getId());
        effect.setDirectorId(entity.getDirectorId());
        effect.setType(entity.getType());
        effect.setUrl(entity.getUrl());
        effect.setName(entity.getName());
        effect.setExtraInfo(entity.getExtraInfo());
        effect.setLocation(entity.getLocation());
        effect.setStatus(entity.getStatus());
        effect.setOpUser(entity.getOpUser());

        return effect;
    }

    private String encodeToUTF8(String raw) {
        try {
            String newStr = URLEncoder.encode(raw, "UTF-8");
            logger.info("[convertString] raw = {}, newStr = {}", raw, newStr);
            newStr = newStr.replace("+", " ");
            return newStr;
        } catch (UnsupportedEncodingException e) {
            logger.info("[convertString] e = " + e);
            return raw;
        }
    }

    // 添加导播台默认素材
    private void createDefaultEffects(int directorId, long programQipuId) {
        logger.info("[createDefaultEffects][directorId={}][programQipuId={}]", directorId, programQipuId);
        List<ProgramDirectorEffect> effects = getPdService().createDefaultEffects(directorId, programQipuId);

        SimpleDateFormat sdf = new SimpleDateFormat("YYYY/MM/dd HH:mm:ss.SSS");
        logger.info("[notifyAddEffect] start {}", sdf.format(new Date()));

        queue = new ConcurrentLinkedQueue<>(effects);

        ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            exec.execute(new EffectAddExecutor());
        }
        exec.shutdown();
        try {
            while (!exec.awaitTermination(30, TimeUnit.SECONDS)) ;
        } catch (InterruptedException e) {
            logger.info("[createDefaultEffects][task][awaitTermination][exception={}]", e);
        }

//        for(ProgramDirectorEffect effect: effects) {
//            try {
//                notifyAddEffectResource(effect, "system", effect.getId(), false);
//            } catch (Exception e) {
//                logger.info("[createDefaultEffects][effectId={}] e = " + e, effect.getId());
//            }
//        }
        logger.info("[notifyAddEffect] end {}", sdf.format(new Date()));
    }

    private class EffectAddExecutor implements Runnable {
        private SimpleDateFormat sdf = new SimpleDateFormat("YYYY/MM/dd HH:mm:ss.SSS");

        @Override
        public void run() {
            ProgramDirectorEffect entity;
            while (true) {
                entity = null;
                synchronized (queue) {
                    if (!queue.isEmpty()) {
                        entity = queue.poll();
                    }
                }
                // 无任务退出
                if (entity == null) {
                    break;
                }

                logger.info("[EffectAddExecutor][effectId={}] start {}", entity.getId(), sdf.format(new Date()));
                notifyAddEffectResource(entity, "system", entity.getId(), false);
                logger.info("[EffectAddExecutor][effectId={}] end {}", entity.getId(), sdf.format(new Date()));
            }
        }
    }

    private void recycleSignalPreviewUrl(ProgramDirector programDirector) {
        try {
            // recycle preview urls
            TFilter tFilter = new TFilter();
            Map<String, String> params = new HashMap<>();
            params.put("EQI_directorId", programDirector.getId() + "");
            params.put("EQI_isDeleted", 0 + "");
            params.put("EQI_signalType", "2");
            tFilter.setFilters(params);
            List<TProgramDirectorResource> programDirectorResourceList = getPrService().getList(tFilter);
            for (TProgramDirectorResource resource : programDirectorResourceList) {
                if (StringUtils.isNotEmpty(resource.getSignalPreviewUrl())) {
                    JSONObject jsonResult = ApiDirectorUtil.stopPreviewUrl(resource.getProgramQipuId() + "", resource.getSignalPreviewUrl());
                    logger.info("[recycleSignalPreviewUrl][recycle preview url][url={}][result={}]",
                            resource.getSignalPreviewUrl(), jsonResult.toJSONString());
                }
            }
        } catch (Exception e) {
            logger.info("[recycleSignalPreviewUrl][recycle preview url] e ", e);
        }
    }

    private void writeProgramLog(long programId, int type, String descr) {
        WriteSystemLogUtil.getInstance().writeProgramLog(programId, type, descr);
    }

    private void writeProgramLogByQipuId(long programQipuId, int type, String descr) {
        try {
            ProgramService service = getProgramService();
            ProgramData programData = service.findProgramDataByQipuId(programQipuId);
            writeProgramLog(programData.getId(), type, descr);
        } catch (Exception e) {
            logger.info("[writeProgramLogByQipuId] e = " + e);
        }
    }

    @Override
    public int addCommentary(TProgramDirectorCommentary entity) throws TException {
        if (entity != null) {
            try {
                // check 是否已经创建了8个解说了
                int count = getCommentaryCount(entity.getProgramQipuId() + "", entity.getDirectorId() + "");
                if (count >= 8) {
                    return ERROR_COMMENTARY_COUNT_OVERFLOW;
                }


                ProgramDirectorResource resourceEntity = new ProgramDirectorResource();

                // necessary values
                resourceEntity.setDirectorId(entity.getDirectorId());
                resourceEntity.setProgramQipuId(entity.getProgramQipuId());
                resourceEntity.setSignalName(entity.getName());
                resourceEntity.setSignalUrl(entity.getStreamUrl());
                resourceEntity.setVolumn("50");

                resourceEntity.setResourceType(ProgramDirectorResource.RESOURCE_TYPE_COMMENTARY);

                ProgramDirectorResource newEntity = getPrService().add(resourceEntity);
                int entityId = newEntity.getId();

                if (entityId < 0) {
                    return ERROR_EXCEPTION;
                }

                if (entity.getName().equals("")) {
                    newEntity.setSignalName(String.format(COMMENTARY_DEFAULT_NAME, newEntity.getId()));
                    getPrService().update(newEntity);
                }

                return entityId;
            } catch (Exception e) {
                logger.error("[addCommentaryEntity] e = " + e);
                return ERROR_EXCEPTION;
            }
        }
        return ERROR_NO_ENTITY;
    }

    @Override
    public int editCommentary(int id, String name, long programQipuId, String streamUrl, String volumn, int status) throws TException {
        try {
            ProgramDirectorResource entity = getPrService().get(id);
            if (entity != null && entity.getStatus() >= 0) {
                if (StringUtils.isNotBlank(name)) {
                    entity.setSignalName(name);
                }
                if (StringUtils.isNotBlank(streamUrl)) {
                    entity.setSignalUrl(streamUrl);
                }
                if (StringUtils.isNotBlank(volumn)) {
                    entity.setVolumn(volumn);
                }
                if (status >= -1) {
                    entity.setStatus(status);
                }

                getPrService().update(entity);

                if (status == 2) {
                    JSONObject result = ApiDirectorUtil.stopCommentary(String.valueOf(programQipuId), String.valueOf(id));
//                    writeDirectorLog();
                }


            } else {
                return ERROR_NO_ENTITY;
            }
        } catch (Exception e) {
            logger.error("[editCommentaryEntity] e = " + e);
            return ERROR_EXCEPTION;
        }
        return RESPONSE_SUC;
    }

    @Override
    public int deleteCommentary(int id) throws TException {
        try {
            ProgramDirectorResource entity = getPrService().get(id);
            if (entity != null && entity.getStatus() == 1) {
                return ERROR_COMMENTARY_IS_PLAYING;
            } else if (entity != null && entity.getStatus() >= 0) {
                entity.setStatus(-1);

                getPrService().update(entity);
            } else {
                return ERROR_NO_ENTITY;
            }
        } catch (Exception e) {
            logger.error("[deleteCommentaryEntity] e = " + e);
            return ERROR_EXCEPTION;
        }
        return RESPONSE_SUC;
    }

    @Override
    public List<TProgramDirectorCommentary> getCommentaryList(TFilter filter) {
        try {
            IProgramDirectorResourceService service = (IProgramDirectorResourceService) ApplicationContextUtil.getBean(IProgramDirectorResourceService.class);
            return service.getCommentaryList(filter);
        } catch (Exception e) {
            logger.info("[getCommentaryList] exception = " + e);
            return new ArrayList<TProgramDirectorCommentary>();
        }
    }

    public int getCommentaryCount(String programQipuId, String directorId) {

        TFilter tFilter = new TFilter();
        Map<String, String> params = new HashMap<String, String>();
        params.put("EQI_directorId", directorId);
        params.put("EQL_programQipuId", programQipuId);
        params.put("EQI_resourceType", "2");
        params.put("GEI_status", "0");

        tFilter.setFilters(params);

        List<TProgramDirectorCommentary> alist = getCommentaryList(tFilter);

        return alist.size();

    }

    private boolean isDirectorChanged(ProgramDirector oldEntity, TProgramDirector newEntity) {
        boolean result = false;

        if (oldEntity.getDelay() != newEntity.getDelay() || !oldEntity.getOutputUrl().equals(newEntity.getOutputUrl()) ||
                !oldEntity.getOutputStreamType().equals(newEntity.getOutputStreamType())) {
            result = true;
        }

        return result;
    }

    @Override
    public int setDirectorResourceId(long programQipuId, int playResourceId, int downResourceId) throws TException {
        try {
            ProgramDirector programDirector = getPdService().getByProgramQipuId(programQipuId);
            if (programDirector == null) {
                return ERROR_NO_ENTITY;
            }
            ProgramDirectorResource programDirectorResource = getPrService().get(playResourceId);
            if (programDirectorResource == null) {
                return ERROR_NO_ENTITY;
            }
            writeDirectorLog(programDirector.getId(), Constants.DirectorLogType.DIRECTOR_SWITCH_RESOURCE.getIndex(),
                    "downResourceId: " + downResourceId + " | playResourceId: " + playResourceId + " | programDirector.resourceId(down): " + programDirector.getResourceId());
            getPdService().updateCurResourceId(programDirector.getId(), playResourceId);
            return RESPONSE_SUC;
        } catch (Exception e ) {
            logger.error("[setDirectorResourceId][programQipuId=" + programQipuId + "]", e);
            return ERROR_EXCEPTION;
        }
    }
}

